//
// AWS Manager - A free AWS console application demonstrating advanced concepts
// Copyright (C) 2008-2010 Sean O'Dell. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.awsmanager.common;

import com.sun.data.provider.RowKey;
import com.sun.data.provider.impl.ObjectListDataProvider;
import com.sun.webui.jsf.model.Option;
import com.xerox.amazonws.ec2.DescribeImageAttributeResult;
import com.xerox.amazonws.ec2.EC2Exception;
import com.xerox.amazonws.ec2.ImageAttribute;
import com.xerox.amazonws.ec2.ImageDescription;
import com.xerox.amazonws.ec2.ImageListAttribute;
import com.xerox.amazonws.ec2.ImageListAttributeItem;
import com.xerox.amazonws.ec2.InstanceType;
import com.xerox.amazonws.ec2.Jec2;
import com.xerox.amazonws.ec2.Jec2.ImageListAttributeOperationType;
import java.util.ArrayList;
import java.util.List;

import com.xerox.amazonws.ec2.LaunchConfiguration;
import com.xerox.amazonws.ec2.LaunchPermissionAttribute;
import com.xerox.amazonws.ec2.ReservationDescription;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Sean ODell
 */
public class EC2ImageDataProvider extends ObjectListDataProvider {

    private ArrayList ec2ImageList = new ArrayList();
    private ArrayList ec2AKIList = new ArrayList();
    private ArrayList ec2ARIList = new ArrayList();

    private EC2Connection ec2connection;

    /** Creates a new instance of AddressDataProvider */
    public EC2ImageDataProvider() {
        setList(ec2ImageList);
        setObjectType(EC2Image.class);
    }

    public void load(EC2Connection ec2connection, Properties awsProps) {

        clearObjectList();
        ec2AKIList = new ArrayList();
        ec2ARIList = new ArrayList();

        if (ec2connection == null) {
            this.ec2connection = null;
            return;
        } else {
            this.ec2connection = ec2connection;
        }

        if ((this.ec2connection = ec2connection) == null) {
            return;
        }

        List<String> params = new ArrayList<String>();
        ArrayList<String> ec2Regions = ec2connection.getEc2RegionNames();
        EC2Region ec2RegionInfo = null;

        for (String ec2Region : ec2Regions) {

            ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2Region);
            List<ImageDescription> images = null;

            try {
                Jec2 ec2 = ec2RegionInfo.getRegionConnection();
                images = ec2.describeImages(params);
            } catch (EC2Exception ex) {
                Logger.getLogger(EC2ImageDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }

            if (images != null) {
                for (ImageDescription img : images) {
                    if (img.getImageState().equals("available")) {
                        EC2Image ec2Image = new EC2Image();
                        ec2Image.setimageId(img.getImageId());
                        ec2Image.setimageLocation(img.getImageLocation());
                        ec2Image.setimageOwnerId(img.getImageOwnerId());
                        ec2Image.setimageState(img.getImageState());
                        ec2Image.setisPublic(img.isPublic());
                        ec2Image.setImageRegion(ec2Region);
                        if ((img.getImageId().startsWith("ami"))
                            || (img.getImageId().startsWith("emi"))) {
                            getList().add(ec2Image);
                        } else if ((img.getImageId().startsWith("aki"))
                            || (img.getImageId().startsWith("eki"))) {
                            ec2AKIList.add(ec2Image);
                        } else if ((img.getImageId().startsWith("ari"))
                            || (img.getImageId().startsWith("eri"))) {
                            ec2ARIList.add(ec2Image);
                        }
                    }
                }
            }
        }
    }

    public EC2Image getImage(RowKey rowKey) {
        EC2Image ec2Image = (EC2Image) getObject(rowKey);
        return ec2Image;
    }

    public EC2Image getImage(String region, String id) {
        EC2Image ec2Image = null;
        for (int i = 0; i < ec2ImageList.size(); i++) {
            ec2Image = (EC2Image) ec2ImageList.get(i);
            if ((ec2Image.getImageRegion().equals(region)) &&
                    (ec2Image.getimageId().equals(id))) {
                return ec2Image;
            }
        }
        return ec2Image;
    }

    public int getImageIndex(String region, String id) {
        for (int i = 0; i < ec2ImageList.size(); i++) {
            EC2Image ec2Image = (EC2Image) ec2ImageList.get(i);
            if ((ec2Image.getImageRegion().equals(region)) &&
                    (ec2Image.getimageId().equals(id))) {
                return i;
            }
        }
        return -1;
    }

    public String launchInstances(Map launchInstanceInfo) {

        String statusMsg = new String();
        String type = (String) launchInstanceInfo.get("instType");
        Integer instCount = (Integer) launchInstanceInfo.get("instCount");
        String keyPair = (String) launchInstanceInfo.get("instKeyPair");
        String zone = (String) launchInstanceInfo.get("instZone");
        byte[] userdata = (byte[]) launchInstanceInfo.get("userdata");
        ArrayList launchInstanceList = (ArrayList) launchInstanceInfo.get("instRowKeys");
        ArrayList securityGroups = (ArrayList) launchInstanceInfo.get("instSecurityGroups");
        String ec2AKI = (String) launchInstanceInfo.get("aki");
        String ec2ARI = (String) launchInstanceInfo.get("ari");

        String ec2RegionName = (String) ec2connection.getEc2ZoneToRegion().get(zone);
        EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2RegionName);

        for (int i = 0; i < launchInstanceList.size(); i++) {

            EC2Image ec2Image = getImage((RowKey) launchInstanceList.get(i));
            String imageID = ec2Image.getimageId().toString();
            statusMsg = statusMsg + "\nStatus for image " + imageID + ":\n";

            try {
                LaunchConfiguration lc = new LaunchConfiguration(imageID);
                lc.setInstanceType(InstanceType.getTypeFromString(type));
                lc.setMinCount(instCount.intValue());
                lc.setMaxCount(instCount.intValue());
                lc.setAvailabilityZone(zone);
                lc.setSecurityGroup(securityGroups);
                lc.setKeyName(keyPair);
                lc.setUserData(userdata);
                if (!ec2AKI.equals("")) {
                    lc.setKernelId(ec2AKI);
                }
                if (!ec2ARI.equals("")) {
                    lc.setRamdiskId(ec2ARI);
                }

                ReservationDescription reservationDescription = ec2RegionInfo.getRegionConnection().runInstances(lc);

                if (reservationDescription != null) {
                    statusMsg = statusMsg + "  Reservation ID: " + reservationDescription.getReservationId() + "\n";
                    List<ReservationDescription.Instance> instanceInfo = reservationDescription.getInstances();
                    for (int j = 0; j < instanceInfo.size(); j++) {
                        statusMsg = statusMsg + "\n    Instance ID: " + instanceInfo.get(j).getInstanceId() + "\n";
                        statusMsg = statusMsg + "      Instance type    : " + instanceInfo.get(j).getInstanceType() + "\n";
                        statusMsg = statusMsg + "      Availability zone: " + instanceInfo.get(j).getAvailabilityZone() + "\n";
                        statusMsg = statusMsg + "      State            : " + instanceInfo.get(j).getState() + "\n";
                        statusMsg = statusMsg + "      Kernel ID        : " + instanceInfo.get(j).getKernelId() + "\n";
                        statusMsg = statusMsg + "      RAM Disk ID      : " + instanceInfo.get(j).getRamdiskId() + "\n";
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                statusMsg = statusMsg + "  Error: " + e.getMessage() + "\n";
            }
        }
        return statusMsg;
    }

    public String regAMIs(Map regAMIinfo) {

        if (this.ec2connection == null) {
            return "Connection to AWS timed out.";
        } else {
            if(this.ec2connection.getEc2RegionInfo() == null) {
                return "Connection to AWs timed out.";
            }
        }

        String statusMsg = new String();
        ArrayList manifestList = (ArrayList) regAMIinfo.get("amiManifestList");
        String region = (String) regAMIinfo.get("amiRegion");

        EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(region);

        for (int i = 0; i < manifestList.size(); i++) {
            try {
                statusMsg = statusMsg + "Registered AMI: " + region + ", " +
                        ec2RegionInfo.getRegionConnection().registerImage((String) manifestList.get(i)) + "\n";
            } catch (EC2Exception ex) {
                statusMsg = statusMsg + "Error: " + ex + "\n";
            }
        }
        return statusMsg;
    }

    public String deregAMIs(RowKey[] selectedRowKeys) {
        String statusMsg = new String();

        for (int i = 0; i < selectedRowKeys.length; i++) {
            RowKey rowKey = selectedRowKeys[i];
            EC2Image ec2image = getImage(rowKey);
            EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(ec2image.getImageRegion());
            try {
                ec2RegionInfo.getRegionConnection().deregisterImage((String) ec2image.getimageId());
                statusMsg = statusMsg + "De-registered AMI: " + ec2image.getImageRegion() + ", " + ec2image.getimageId() + "\n";
            } catch (EC2Exception ex) {
                statusMsg = statusMsg + "Error: " + ex + "\n";
            }
        }
        return statusMsg;
    }

    public EC2AMILaunchAttributes getImageAttribute(String region, String imageid) {

        EC2AMILaunchAttributes ec2AMILaunchAttributes = null;
        ArrayList amiAttributeList = null;

        DescribeImageAttributeResult describeImageAttributeResult = null;
        EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(region);

        try {
            describeImageAttributeResult = ec2RegionInfo.getRegionConnection().describeImageAttribute(imageid,
                    ImageAttribute.ImageAttributeType.launchPermission);
        } catch (EC2Exception ex) {
            Logger.getLogger(EC2ImageDataProvider.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (describeImageAttributeResult != null) {

            ec2AMILaunchAttributes = new EC2AMILaunchAttributes();
            ec2AMILaunchAttributes.setAmiID(imageid);
            ec2AMILaunchAttributes.setGrantPublic(false);
            ec2AMILaunchAttributes.setAwsAccountIDs(null);

            ImageListAttribute imageListAttribute =
                    describeImageAttributeResult.getImageListAttribute();

            if (imageListAttribute != null) {
                Set<ImageListAttributeItem> imageListAttributeItems =
                        imageListAttribute.getImageListAttributeItems();
                if (imageListAttributeItems != null) {
                    if (!imageListAttributeItems.isEmpty()) {
                        amiAttributeList = new ArrayList();
                        Iterator iter = imageListAttributeItems.iterator();
                        if (iter.hasNext()) {
                            while (iter.hasNext()) {
                                ImageListAttributeItem imageListAttributeItem =
                                        (ImageListAttributeItem) iter.next();
                                amiAttributeList.add(imageListAttributeItem.getValue());
                                if (imageListAttributeItem.getValue().equalsIgnoreCase("all")) {
                                    ec2AMILaunchAttributes.setGrantPublic(true);
                                }
                            }
                            ec2AMILaunchAttributes.setAwsAccountIDs(amiAttributeList);
                        }
                    }
                }
            }
        }

        return ec2AMILaunchAttributes;
    }

    public EC2AMILaunchAttributes modifyImageAttribute(
            EC2AMILaunchAttributes ec2AMILaunchAttributes) {

        String statusMsg = new String();
        EC2AMILaunchAttributes ec2AMILaunchAttributesResult = new EC2AMILaunchAttributes();
        String region = ec2AMILaunchAttributes.getRegion();
        int successCount = 0;
        int errorCount = 0;

        if (region == null) {
            statusMsg = statusMsg + "Error: region is not valid.";
            ec2AMILaunchAttributesResult.setStatsMsg(statusMsg);
            return ec2AMILaunchAttributesResult;
        }

        if (region.equals("")) {
            statusMsg = statusMsg + "Error: region is not valid.";
            ec2AMILaunchAttributesResult.setStatsMsg(statusMsg);
            return ec2AMILaunchAttributesResult;
        }

        EC2Region ec2RegionInfo = (EC2Region) ec2connection.getEc2RegionInfo().get(region);

        if (ec2RegionInfo == null) {
            statusMsg = statusMsg + "Connection to AWS expired.";
            ec2AMILaunchAttributesResult.setStatsMsg(statusMsg);
            return ec2AMILaunchAttributesResult;
        }

        try {
            ec2RegionInfo.getRegionConnection().resetImageAttribute(
                    ec2AMILaunchAttributes.getAmiID(),
                    ImageAttribute.ImageAttributeType.launchPermission);
        } catch (EC2Exception ex) {
            Logger.getLogger(EC2ImageDataProvider.class.getName()).log(Level.SEVERE, null, ex);
        }

        if (ec2AMILaunchAttributes.isGrantPublic()) {
            ImageListAttribute imageListAttribute = new LaunchPermissionAttribute();
            imageListAttribute.addImageListAttributeItem(
                    ImageListAttribute.ImageListAttributeItemType.group, "all");
            try {
                ec2RegionInfo.getRegionConnection().modifyImageAttribute(
                        ec2AMILaunchAttributes.getAmiID(), imageListAttribute,
                        ImageListAttributeOperationType.add);
                EC2Image ec2Image = this.getImage(region,
                        ec2AMILaunchAttributes.getAmiID());
                int imageIndex = this.getImageIndex(region,
                        ec2AMILaunchAttributes.getAmiID());
                ec2Image.setisPublic(true);
                this.ec2ImageList.set(imageIndex, ec2Image);
                statusMsg = statusMsg + "Public permission granted.\n";
            } catch (EC2Exception ex) {
                Logger.getLogger(EC2ImageDataProvider.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            EC2Image ec2Image = this.getImage(region,
                    ec2AMILaunchAttributes.getAmiID());
            int imageIndex = this.getImageIndex(region,
                    ec2AMILaunchAttributes.getAmiID());
            ec2Image.setisPublic(false);
            this.ec2ImageList.set(imageIndex, ec2Image);
        }

        ArrayList<String> awsAccountIDs = ec2AMILaunchAttributes.getAwsAccountIDs();
        if (awsAccountIDs != null) {
            if (!awsAccountIDs.isEmpty()) {
                for (String awsAccountId : awsAccountIDs) {
                    if (!awsAccountId.equals("all")) {
                        ImageListAttribute imageListAttribute = new LaunchPermissionAttribute();
                        imageListAttribute.addImageListAttributeItem(
                                ImageListAttribute.ImageListAttributeItemType.userId, awsAccountId);
                        try {
                            ec2RegionInfo.getRegionConnection().modifyImageAttribute(
                                    ec2AMILaunchAttributes.getAmiID(),
                                    imageListAttribute, ImageListAttributeOperationType.add);
                            successCount++;
                        } catch (EC2Exception ex) {
                            Logger.getLogger(EC2ImageDataProvider.class.getName()).log(Level.SEVERE, null, ex);
                            errorCount++;
                        }
                    }
                }
            }
        }

        if (successCount > 0) {
            statusMsg = statusMsg + "Permission granted for " + successCount + " account IDs.\n";
        }

        if (errorCount > 0) {
            statusMsg = statusMsg + "Permission not granted for " + errorCount + " invalid account IDs.\n";
        }

        ec2AMILaunchAttributesResult.setStatsMsg(statusMsg);
        return ec2AMILaunchAttributesResult;
    }

    public ArrayList getEc2AKIList() {
        return ec2AKIList;
    }

    public void setEc2AKIList(ArrayList ec2AKIList) {
        this.ec2AKIList = ec2AKIList;
    }

    public ArrayList getEc2ARIList() {
        return ec2ARIList;
    }

    public void setEc2ARIList(ArrayList ec2ARIList) {
        this.ec2ARIList = ec2ARIList;
    }

    public Option[] getEc2ARIOptions() {
        int i = 0;
        Option[] ec2ARIOptions = new Option[getEc2ARIList().size() + 1];
        EC2Image ec2Image = new EC2Image();
        ec2ARIOptions[0] = new Option("");

        for (i = 1; i <= getEc2ARIList().size(); i++) {
            ec2Image = (EC2Image) getEc2ARIList().get(i - 1);
            ec2ARIOptions[i] = new Option(ec2Image.getimageId());
        }
        return ec2ARIOptions;
    }
    public Option[] getEc2AKIOptions() {
        int i = 0;
        Option[] ec2AKIOptions = new Option[getEc2AKIList().size() + 1];
        EC2Image ec2Image = new EC2Image();
        ec2AKIOptions[0] = new Option("");

        for (i = 1; i <= getEc2AKIList().size(); i++) {
            ec2Image = (EC2Image) getEc2AKIList().get(i - 1);
            ec2AKIOptions[i] = new Option(ec2Image.getimageId());
        }
        return ec2AKIOptions;
    }


}
